<?php

    /**
    * Mukei Development Framework
    *
    * Mukei is a development framework system created to provide developers
    * two main features: a plugin architecture which and expand the
    * functionality of the system and an event system which allows exansion of
    * existing plugins without modifing the original code.  The Mukei
    * development framework system can speed up development of new web
    * applications and reduce maintenance time of existing code.
    *
    * This file is part of Mukei.
    *
    * Mukei is free software; you can redistribute it and/or modify it under
    * the terms of the GNU General Public License as published by the Free
    * Software Foundation; either version 3 of the License, or (at your option)
    * any later version.
    *
    * Mukei is distributed in the hope that it will be useful, but WITHOUT ANY
    * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    * details.
    *
    * You should have received a copy of the GNU General Public License
    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    *
    * @package   Mukei
    * @version   0.2
    * @author    Kevin Herrera
    * @license   http://www.gnu.org/licenses/gpl.txt GNU GPL v3
    * @copyright Copyright (c) 2007 Kevin Herrera.
    */

    // Run Mukei.
    new Mukei ( );

    /**
    * Mukei System Class
    *
    * This is the "core" of the Mukei development framework system.  All vital
    * system processes are performed within this class through private
    * methods.  The generated information is also stored in private methods to
    * protect it from accidental modifications while the system is running.
    * To modify data on the fly, it is suggested that you create an event
    * plugin for the appropriate event.  If you would like to expand the
    * functionality of the development framework system, it is suggested that
    * your create a system plugin.  If you would like to create a web
    * application using the framework and plugins, it is suggested that you
    * create a client plugin.
    *
    * An Event:
    *
    * An event is a specific time in the system where a specific process is
    * executed.  When this event happens is determined by when and where the
    * core method, trigger(), is called.  To be able to "listen" to this
    * event, or have a function or method called at this specific point, a
    * function or method must be "attached" to the event.  To attach a
    * "listener" to the event, you must call the core method, attach(), with
    * the appropriate arguments (a valid PHP callback).
    *
    * It is also possible to "register" an event.  To register an event means
    * to create it and possibly restrict it so that only a specific function
    * or method may trigger the event.  You can attach listeners to an event
    * before it has been registered.  If an event is registered after
    * listeners have been attached to the event, the registered event will
    * inherit all of the listeners.  To register an event, the core method,
    * register(), must be called.  You may also "unregister" an event with
    * or without clearing all of the listeners.  To unregister an event, the
    * core method, unregister(), must be called.
    *
    * An Event Plugin:
    *
    * An event plugin is a PHP script that contains functions or methods that
    * will be attached by the script once the script has been loaded by the
    * system.  This script may perform other functions than attach or detach
    * listeners but it is not recommended.  What an event plugin may also do
    * is register or unregister events.
    *
    * A Client Plugin:
    *
    * A client plugin is a PHP script without and specific structure or
    * requirements.  A client plugin can be as simple as a print statement or
    * as complex as a multi-threaded server.  A client plugin is a web
    * application developed specifically to use the Mukei development
    * framework system.
    *
    * A Library Plugin:
    *
    * A library plugin is a PHP script that contains functions or methods that
    * are not important enough to be loaded every single time Mukei is
    * executed.  A library plugin is only loaded when another plugin makes a
    * request for it by calling the core method, load().  An example of a
    * library plugin would be a class that can compress and decompress
    * compressed archive files or manipulate images.
    *
    * A System Plugin:
    *
    * A system plugin is a PHP script similar to that of a library plugin
    * except that it is specially designed to be loaded every single time
    * Mukei is executed.  The extra code allows for the core to predict
    * certain possible processes as well as check for dependencies, perform
    * plugin synchronizations (when plugins are loaded out of order), and
    * make the system plugin's functions and methods available to all other
    * plugins.
    *
    * @package Mukei
    * @final
    */
    final class Mukei
    {
        /**#@+
        * @access public
        * @var    const
        */
        const NAME    = "Nairohe";
        const VERSION = "0.2";
        /**#@-*/

        /**#@+
        * @access private
        * @var    array
        */
        private $_config   = array( );
        private $_consts   = array( );
        private $_depend   = array( );
        private $_events   = array( );
        private $_library  = array( );
        private $_registry = array( );
        private $_sync     = array( );
        private $_temp     = array( );
        /**#@-*/

        /**
        * Class Constructor
        *
        * This method is the core class constructor.  This method creates a
        * global called $M and stores this class's object in the global.  This
        * method also calls various core methods that collect information on
        * the server, load various files and scripts, and execute all of the
        * loaded scripts.  If at any point any of the core methods fails to
        * perform its duty, a fatal error will be triggered to prevent the
        * system from continuing.  This is to prevent unexpected results from
        * partially loaded scripts and possibly corrupted data.
        *
        * If all of the core methods have completed their routines, an event
        * called "m_final" will be triggered.  This is the final event before
        * the system exits.  This is event was created for the client plugin
        * sub-system but may be used for other purposes as well.
        *
        * @access public
        * @global object $M
        * @uses   Mukei::_check()
        * @uses   Mukei::_config()
        * @uses   Mukei::_define()
        * @uses   Mukei::_depend()
        * @uses   Mukei::_events()
        * @uses   Mukei::_init()
        * @uses   Mukei::_system()
        * @uses   Mukei::_trigger()
        * @return object
        */
        public function __construct ( )
        {
            // Create global.
            global $M;

            // Set global.
            $M = $this;

            // Initialize.
            $this->_init  ( );
            $this->_config( );
            $this->_events( );
            $this->_define( );
            $this->_check ( );
            $this->_system( );
            $this->_depend( );

            // Trigger event.
            $this->trigger( "m_final" );
        }

        /**
        * Check Required Directories
        *
        * This core method will perform a check on all of the required system
        * directories using the core function, m_path().  If the core function,
        * m_path(), returns false on any of the required system directories,
        * a fatal error will be triggered.  If there are no issues with any of
        * the require system directories, the system will continue.  This
        * method also triggers two events, "m_check_pre" and "m_check_post".
        * The event "m_check_pre" will be triggered immediately before the
        * directories are checked.  The event "m_check_post" will be triggered
        * immediately after all the directories have been successfully checked.
        * The array of directories to be checked will be past to both events'
        * listeners.
        *
        * @access private
        * @uses   m_path()
        * @uses   Mukei::trigger()
        * @return void
        */
        private function _check ( )
        {
            // List required directories.
            $required = array(

                'data'      => array( true, true  ),
                'events'    => array( true, true  ),
                'library'   => array( true, false ),
                'system'    => array( true, false ),
                'temp'      => array( true, true  ),

            );

            // Trigger event.
            $this->trigger( "m_check_pre", $required );

            // Walk through directories.
            foreach ( $required as $dir => $perms )
            {
                // Check the directory.
                if ( !m_path( M_BASE_DIR . $dir,
                              M_DIRECTORY,
                              $perms[0],
                              $perms[1] ) )
                {
                    // Report fatal error.
                    trigger_error( "System directory, $dir, has errors.",
                                   E_USER_ERROR );
                }
            }

            // Trigger event.
            $this->trigger( "m_check_post", $required );
        }

        /**
        * Load System Settings
        *
        * This core method will attempt to load the configuration settings file
        * created specifically for the system.  Since certain constants are
        * not defined at this point, the core function m_data() cannot be used
        * to retrieve the configuration settings file.  If this method
        * encounters any issues while attempting to load and parse the
        * configuration settings file, a fatal error will be triggered.  These
        * settings are required for the system to function properly.  If the
        * settings have been successfully loaded, the system will continue.
        *
        * @access private
        * @uses   m_data_parse()
        * @return void
        */
        private function _config ( )
        {
            // Create path.
            $path = $this->_temp['base_dir'] .
                    "data/System"            .
                    $this->_temp['file_ext'];

            // File exists?
            if ( file_exists( $path ) )
            {
                // Is a file?
                if ( is_file( $path ) )
                {
                    // Is readable?
                    if ( is_readable( $path ) )
                    {
                        // Read the contents?
                        if ( $contents = file_get_contents( $path ) )
                        {
                            // Unable to parse?
                            if ( ( $this->_config = m_data_parse( $contents ) )
                                 === false )
                            {
                                // Report fatal error.
                                trigger_error( "Unable to load system " .
                                               "settings.",
                                               E_USER_ERROR );
                            }
                        }

                        // Unable to read contents?
                        else
                        {
                            // Report fatal error.
                            trigger_error( "Unable to read system settings " .
                                           "file.",
                                           E_USER_ERROR );
                        }
                    }

                    // Is not readable?
                    else
                    {
                        // Report fatal error.
                        trigger_error( "System does not have permission to " .
                                       "read the contents of the system "    .
                                       "settings file.",
                                       E_USER_ERROR );
                    }
                }

                // Is not a file?
                else
                {
                    // Report fatal error.
                    trigger_error( "System settings path is not a file.",
                                   E_USER_ERROR );
                }
            }

            // File missing?
            else
            {
                // Report fatal error.
                trigger_error( "System settings file, $path, does not exist.",
                               E_USER_ERROR );
            }
        }

        /**
        * Declare System Constants
        *
        * This core method finalizes all of the data collected from the private
        * core method, _init(), by declaring constants using the collected
        * values.  The constants, however, can be declared before this method
        * does by listening to the "m_define_pre" event.  Since this method
        * uses m_define() to declare the constants, any constant created
        * earlier with the same name will remain and the declaration attempt
        * made here will be ignored.  This is for useful when the information
        * assumed by the system is incorrect and you need to alter the values.
        * This method has a total of two events.  The first is "m_define_pre",
        * which is triggered immediately before any constants are declared,
        * and the second is "m_define_post", which is triggered immediately
        * after all of the constants have been declared.
        *
        * @access private
        * @uses   m_define()
        * @uses   m_scan()
        * @uses   Mukei::trigger()
        * @return void
        */
        private function _define ( )
        {
            // Trigger event.
            $this->trigger( "m_define_pre" );

            // Declare OS constant.
            m_define( 'M_OS', $this->_temp['os'] );

            // Declare basic path constants.
            m_define( 'M_BASE_DIR', $this->_temp['base_dir'] );
            m_define( 'M_BASE_URL', $this->_temp['base_url'] );
            m_define( 'M_EXT',      $this->_temp['file_ext'] );
            m_define( 'M_INDEX',    $this->_temp['index']    );
            m_define( 'M_SEP',      $this->_temp['path_sep'] );

            // Define protocol constants.
            m_define( 'M_PROTOCOL', $this->_temp['protocol'] );
            m_define( 'M_SECURE',   $this->_temp['secure']   );

            // Scan base directory.
            $dirs = m_scan( M_BASE_DIR,
                            M_DIRECTORY );

            // Walk through directories.
            foreach ( $dirs as $dir )
            {
                // Change case.
                $name = strtoupper( $dir );

                // Create names.
                $name_dir = "M_${name}_DIR";
                $name_url = "M_${name}_URL";

                // Create values.
                $value_dir = M_BASE_DIR . $dir . M_SEP;
                $value_url = M_BASE_URL . $dir . "/";

                // Declare constants.
                m_define( $name_dir, $value_dir );
                m_define( $name_url, $value_url );
            }

            // Trigger event.
            $this->trigger( "m_define_post" );
        }

        /**
        * Check Dependencies
        *
        * This core method will check the dependencies list generated by
        * another core method called depend().  After this method has gone
        * through the dependencies list and the list is not empty, an HTML
        * list will be created to list in detail which plugins are missing.
        * Ater the list has been generated a fatal error will be triggered
        * stating the problem and will also include the list generated.
        *
        * @access private
        * @return void
        */
        private function _depend ( )
        {
            // Have dependencies?
            if ( !empty( $this->_depend ) )
            {
                // Create list.
                $list = array( );

                // Walk through dependencies array.
                foreach ( $this->_depend as $name => $plugin )
                {
                    // Walk through the plugins dependencies.
                    foreach ( $plugin as $handle => $class )
                    {
                        // Other plugin loaded?
                        if ( isset( $this->$handle ) &&
                             ( get_class( $this->$handle ) === $class ) )
                        {
                            // Remove from list.
                            unset( $plugin[ $handle ] );
                        }
                    }

                    // List not empty?
                    if ( !empty( $plugin ) )
                    {
                        // Add to list.
                        $list[ $name ] = $plugin;
                    }
                }

                // List not empty?
                if ( !empty( $list ) )
                {
                    // Create HTML list.
                    $ul = "<ul>";

                    // Walk through list.
                    foreach ( $list as $name => $plugin )
                    {
                        // Begin item.
                        $ul .= "<li>";

                        // List plugin.
                        $ul .= "$name:";

                        // Begin sub list.
                        $ul .= "<ul>";

                        // Walk through dependencies.
                        foreach ( $plugin as $handle => $class )
                        {
                            // Create item.
                            $ul .= "<li>$handle: $class</li>";
                        }

                        // Finish sub list.
                        $ul .= "</ul>";

                        // Finish item.
                        $ul .= "</li>";
                    }

                    // Finish HTML list.
                    $ul .= "</ul>";

                    // Report fatal error.
                    trigger_error( "The system has detected that certain "    .
                                   "plugins are missing their dependencies. " .
                                   "The following is a list of those plugins" .
                                   ".  Each plugin listed will also have a "  .
                                   "list of the dependencies missing: $ul",
                                   E_USER_ERROR );
                }
            }
        }

        /**
        * Load Event Plugins
        *
        * This core method performs a series of checks on the events directory,
        * scans the contents for event plugins, and attempts to load all of the
        * event plugins allowed.  If the directory does not exist, is not
        * actually a directory (per is_dir()), or is not readable (i.e.
        * insufficient privileges or other issues per is_readable()), the
        * loading of the event plugins will be aborted and the system will
        * continue.  As this method is looping through each event plugin, if
        * it is not listed in the _config['events'] array, it will be skipped.
        * If the plugin is listed in the array but require_once() is unable to
        * load the plugin, a fatal error will be triggered.
        *
        * @access private
        * @return void
        */
        private function _events ( )
        {
            // Create regex.
            $regex = "/" . preg_quote( $this->_temp['file_ext'], "/" ) . "$/";

            // Get path.
            $path = $this->_temp['base_dir'] .
                    "events"                 .
                    $this->_temp['path_sep'];

            // Events directory exists?
            if ( file_exists( $path ) &&
                 is_dir     ( $path ) &&
                 is_readable( $path ) )
            {
                // Scan the directory.
                $contents = scandir( "events" );

                // Walk through contents.
                foreach ( $contents as $content )
                {
                    // Is event plugin?
                    if ( preg_match( $regex, $content ) )
                    {
                        // Allowed to load?
                        if ( in_array( $content, $this->_config['events'] ) )
                        {
                            // Load script.
                            if ( !require_once( $path . $content ) )
                            {
                                // Report fatal error.
                                trigger_error( "Unable to load event " .
                                               "plugin, $content.",
                                               E_USER_ERROR );
                            }
                        }
                    }
                }
            }
        }

        /**
        * System Initialization
        *
        * This core method declares required system constants, collects server
        * information, and creates an array of required system plugin
        * constants.  If any of the basic system constants could not be
        * defined, a fatal error will be triggered.  The values of these
        * constants may not be modified and have a specific reason for having
        * the values they must be defined with.  After declaring the constants,
        * information such as operating system name, current protocol, and
        * other information such as paths and file extensions is collected and
        * stored in a temporary location.  After the necessary information has
        * been collected, an array of recognized system constants is then
        * created.  This array determines which constants are required and what
        * type of values are allowed.
        *
        * @access private
        * @return void
        */
        private function _init ( )
        {
            // Declare constants.
            if ( !define( 'M_ARRAY',    "array"      ) ||
                 !define( 'M_BOOL',     "boolean"    ) ||
                 !define( 'M_DOUBLE',   "double"     ) ||
                 !define( 'M_INTEGER',  "integer"    ) ||
                 !define( 'M_NULL',     "null"       ) ||
                 !define( 'M_OBJECT',   "object"     ) ||
                 !define( 'M_RESOURCE', "resource"   ) ||
                 !define( 'M_STRING',   "string"     ) ||
                 !define( 'M_UNKNOWN',  "unknown"    ) ||
                 !define( 'M_DIRECTORY', "directory" ) ||
                 !define( 'M_FILE',      "file"      ) )
            {
                // Report fatal error.
                trigger_error( "Unable to define basic system constants.",
                               E_USER_ERROR );
            }

            // Get global.
            global $HTTP_SERVER_VARS;

            // Get SERVER global.
            $SERVER = isset( $_SERVER ) ? $_SERVER
                                        : $HTTP_SERVER_VARS;

            // Get operating system.
            $this->_temp['os'] = substr( PHP_OS, 0, 3 );
            $this->_temp['os'] = strtolower( $this->_temp['os'] );

            // No HTTPS?
            if ( empty( $SERVER['HTTPS'] ) )
                $SERVER['HTTPS'] = "off";

            // Get secure information.
            $this->_temp['secure'] = strtolower( $SERVER['HTTPS'] );
            $this->_temp['secure'] = ( $this->_temp['secure'] === "on" )
                                   ? true
                                   : false;

            // Get web protocol.
            $this->_temp['protocol'] = ( $this->_temp['secure'] === true )
                                     ? "https://"
                                     : "http://";

            // Get path seperator.
            $this->_temp['path_sep'] = ( $this->_temp['os'] === "win" )
                                     ? "\\"
                                     : "/";

            // Get base path.
            $this->_temp['base_dir'] = dirname( __FILE__ ) .
                                       $this->_temp['path_sep'];

            // Get base URL.
            $this->_temp['base_url'] = $this->_temp['protocol']       .
                                       $SERVER['HTTP_HOST']           .
                                       dirname( $SERVER['PHP_SELF'] ) . "/";

            // Get index name.
            $this->_temp['index'] = basename( __FILE__ );

            // Get file extension.
            $this->_temp['file_ext'] = explode  ( ".",
                                                  $this->_temp['index'] );
            $this->_temp['file_ext'] = array_pop( $this->_temp['file_ext'] );
            $this->_temp['file_ext'] = "." . $this->_temp['file_ext'];

            // Get declared classes.
            $this->_temp['classes'] = get_declared_classes( );

            // List recognized class constants.
            $this->_consts = array(

                'ADMIN'     => array( false,        M_BOOL       ),
                'AUTHOR'    => array( true,         M_STRING     ),
                'DESC'      => array( true,         M_STRING     ),
                'EMAIL'     => array( false,        M_STRING     ),
                'HANDLE'    => array( true,         M_STRING     ),
                'NAME'      => array( true,         M_STRING     ),
                'REQUIRED'  => array( true,  array( M_DOUBLE,
                                                    M_INTEGER,
                                                    M_STRING   ) ),
                'SUPPORT'   => array( false,        M_STRING     ),
                'SYNC'      => array( false, array( M_ARRAY,
                                                    M_STRING   ) ),
                'VERSION'   => array( true,  array( M_DOUBLE,
                                                    M_INTEGER,
                                                    M_STRING   ) ),
                'WEBSITE'   => array( false,        M_STRING     ),

            );
        }

        /**
        * Load System Plugin
        *
        * This core method performs the actual loading process of another core
        * method, _system().  This method checks to see if the class that must
        * be created by the system plugin already exists.  If it does, a fatal
        * error will be triggered stating the issue.  If the class does not
        * exist, the next check will be on the system plugin file.  If the core
        * method, m_path(), returns the boolean value of false, a fatal error
        * will be triggered.  After the file check has been performed, the
        * system plugin will be loaded.  Once the plugin has been successfully
        * loaded, a check will be made to see if the class was created after
        * loading the plugin.
        *
        * If the class still does not exist, a fatal error will be triggered
        * stating the issue.  This class is required for a system plugin to be
        * properly loaded into the system.  If the class exists, the array
        * created earlier by the core method, _init(), will be used to check
        * the system plugin's class constants.  If a required constant is
        * missing or the values of an existing constant is invalid, a fatal
        * error will be triggered.  If there are no issues with the constants,
        * the constants will be then used to perform various tasks such as
        * synchronization of system plugins, checking for resources, etc...
        *
        * @access private
        * @uses   m_arg()
        * @uses   m_callback()
        * @uses   m_path()
        * @param  string  $plugin System plugin file name.
        * @param  string  $name   System plugin class name.
        * @return void
        */
        private function _load ( $plugin,
                                 $name )
        {
            // Class exists already?
            if ( class_exists( $name ) )
            {
                // Report fatal error.
                trigger_error( "Unable to load system plugin, $plugin. " .
                               " The class, $name, already exists.",
                               E_USER_ERROR );
            }

            // Create path.
            $path = M_SYSTEM_DIR . $plugin;

            // Problems with system plugin file?
            if ( !m_path( $path, M_FILE, true ) )
            {
                // Report fatal error.
                trigger_error( "Unable to load system plugin, $plugin.",
                               E_USER_ERROR );
            }

            // Load system plugin.
            if ( !require_once( $path ) )
            {
                // Report fatal error.
                trigger_error( "Unable to load system plugin, $plugin.",
                               E_USER_ERROR );
            }

            // Class missing?
            if ( !class_exists( $name ) )
            {
                // Report fatal error.
                trigger_error( "Unable to load system plugin, $plugin. " .
                               " The class, $name, is missing.",
                               E_USER_ERROR );
            }

            // Make constants array.
            $constants = array( );

            // Check recognized constants.
            foreach ( $this->_consts as $constant => $props )
            {
                // Is defined?
                if ( $value = @constant( "${name}::${constant}" ) )
                {
                    // Check type.
                    m_arg( $value, $props[1] );

                    // Save value.
                    $constants[ $constant ] = $value;
                }

                // Not defined and required?
                elseif ( $props[0] === true )
                {
                    // Report fatal error.
                    trigger_error( "System plugin, $plugin, did not "      .
                                   "declare the required class constant, " .
                                   "${constant}.",
                                   E_USER_ERROR );
                }
            }

            // Wrong version of the system?
            if ( version_compare( Mukei::VERSION,
                                  $constants['REQUIRED'] ) < 0 )
            {
                // Report fatal error.
                trigger_error( "System plugin, " . $constants['NAME'] . ", " .
                               "requires Mukei v" . $constants['REQUIRED'] .
                               " or greater.",
                               E_USER_ERROR );
            }

            // Handle in use?
            if ( isset( $this->$constants['HANDLE'] ) )
            {
                // Report fatal error.
                trigger_error( "System handle," . $constants['HANDLE'] .
                               ", is already in use.",
                               E_USER_ERROR );
            }

            // Have sync?
            if ( !empty( $constants['SYNC'] ) )
            {
                // Invalid callback?
                if ( !m_callback( array( $name,
                                         $constants['SYNC'] ) ) )
                {
                    // Report fatal error.
                    trigger_error( "System plugin, " . $constants['NAME'] .
                                   ", defined an invalid callback for "   .
                                   "synchronizing.",
                                   E_USER_ERROR );
                }
            }

            // Initialize.
            $this->$constants['HANDLE'] = new $name ( );
        }

        /**
        * Is Event Name Reserved?
        *
        * This core method checks to see if the specified event name is
        * contains the reserved prefix, m_.  If the prefix exists, it will then
        * check to see who the caller is.  If the caller does not match the
        * name of the core class, the boolean value of false will be returned.
        * If the prefix does not exist, the boolean value of false will be
        * returned.  No errors or warnings are triggered in this method since
        * the purpose of this method may vary.
        *
        * @access private
        * @uses   m_arg()
        * @param  string  $event Event name.
        * @return boolean
        */
        private function _reserved ( $event )
        {
            // Check argument.
            m_arg( $event, M_STRING );

            // Is reserved?
            if ( preg_match( "/^m_/", $event ) )
            {
                // Get caller.
                $caller = debug_backtrace( );
                $caller = $caller[2];

                // Have class?
                if ( !empty( $caller['class'] ) )
                {
                    // Class match?
                    if ( $caller['class'] === __CLASS__ )
                    {
                        // Allow.
                        return( false );
                    }
                }

                return( true );
            }

            return( false );
        }

        /**
        * Find and Load System Plugins
        *
        * This core method scans the system directory for system plugins and
        * attempts to load the plugins that are listed in the _config['system']
        * array.  If the plugin is not listed, it will be skipped.  If the
        * plugin is listed, another core method called _load() will be called
        * with the name of the file and the class name of the system plugin.
        * Also, this method triggers two events.  The first event triggered is
        * called "m_system_pre", it is triggered immediately before checking
        * and loading each plugin.  The second event triggered is called
        * "m_system_post", it is triggered immediately after attempting to
        * load all of the system plugins.
        *
        * @access private
        * @uses   m_scan()
        * @uses   Mukei::_load()
        * @uses   Mukei::trigger()
        * @return void
        */
        private function _system ( )
        {
            // Scan for plugins.
            $plugins = m_scan( M_SYSTEM_DIR,
                               M_FILE,
                               "/" . preg_quote( M_EXT, "/" ) . "$/" );

            // Trigger event.
            $this->trigger( "m_system_pre", $plugins );

            // Walk through each plugin.
            foreach ( $plugins as $plugin )
            {
                // Allowed to load?
                if ( in_array( $plugin, $this->_config['system'] ) )
                {
                    // Parse plugin name.
                    $name = explode( ".", $plugin );
                    $name = array_shift( $name );

                    // Attempt load.
                    $this->_load( $plugin,
                                  $name );
                }
            }

            // Trigger event.
            $this->trigger( "m_system_post", $plugins );
        }

        /**
        * Attach Event Listener
        *
        * This core method will add a function or method to a specific event.
        * When another core method, trigger(), is called to perform the
        * specified event, the "attached" function or method (a listener) will
        * be executed along with all of the other listeners that were attached
        * using this method.  The $listener argument is any valid PHP callback.
        * Please see PHP's documentation on what a valid callback is.  To
        * detach an event listener that has been attached by this method, you
        * must call another core method called detach().  It accepts the same
        * exact arguments that were passed to this method.
        *
        * @access public
        * @uses   m_arg()
        * @uses   m_callback()
        * @uses   m_id()
        * @param  string  $event    Event name.
        * @param  mixed   $listener Event listener.
        * @return boolean
        */
        public function attach ( $event,
                                 $listener )
        {
            // Check arguments.
            m_arg( $event,           M_STRING   );
            m_arg( $listener, array( M_ARRAY,
                                     M_STRING ) );

            // Invalid callback?
            if ( !m_callback( $listener ) )
            {
                // Report warning.
                trigger_error( "Invalid event listener for event, $event, " .
                               "provided: $listener",
                               E_USER_WARNING );

                return( false );
            }

            // Generate ID.
            $id = m_id( $listener );

            // New event?
            if ( !isset( $this->_event[ $event ] ) )
            {
                // Create event.
                $this->_event[ $event ] = array( );
            }

            // Listener not already added?
            if ( empty( $this->_event[ $event ][ $id ] ) )
            {
                // Save listener.
                $this->_events[ $event ][ $id ] = $listener;

                return( true );
            }

            // Listener already added?
            else
            {
                // Report warning.
                trigger_error( "Event listener, $id, has already been " .
                               "attached to the event, $event.",
                               E_USER_WARNING );
            }

            return( false );
        }

        /**
        * Get User Defined Classes
        *
        * This core method will get a list of user defined classes (except the
        * Mukei class).  This method exists because for system plugins that
        * require a list of class names for processing but do not need any of
        * PHP's classes or loaded module classes.  This method also exists
        * because PHP has not implemented a function similar to
        * get_defined_classes() for retrieving class names.
        *
        * @access public
        * @return array
        */
        public function classes ( )
        {
            // Get classes.
            $classes = get_declared_classes( );

            // Walk through array.
            foreach ( $classes as $index => $class )
            {
                // In previous array?
                if ( in_array( $class, $this->_temp['classes'] ) )
                {
                    // Remove from array.
                    unset( $classes[ $index ] );
                }
            }

            // Reset indexes.
            $classes = array_values( $classes );

            return( $classes );
        }

        /**
        * Add Dependencies List
        *
        * This core method adds a dependency check list to the _depend array
        * for another core method to use for dependency checking.  The $list
        * argument is an associative array.  The key is the name of the handle
        * and the value is the class name of the plugin.  If this array is not
        * structured properly, a warning will be triggered and the boolean
        * value of false will be returned.
        *
        * @access public
        * @uses   m_arg()
        * @param  array   $list Array of handles and classes.
        * @return boolean
        */
        public function depend ( $list )
        {
            // Check argument.
            m_arg( $list, M_ARRAY );

            // List not empty?
            if ( !empty( $list ) )
            {
                // Get backtrace.
                $name = debug_backtrace( );
                $name = $name[1];

                // Have class?
                if ( !empty( $name['class'] ) )
                {
                    // Relocate.
                    $name = $name['class'];

                    // Walk through array.
                    foreach ( $list as $handle => $class )
                    {
                        // Handle is string?
                        if ( is_string( $handle ) )
                        {
                            // Class is not string?
                            if ( !is_string( $class ) )
                            {
                                // Report warning.
                                trigger_error( "Invalid class name for " .
                                               "dependency check: $class",
                                               E_USER_WARNING );

                                return( false );
                            }
                        }

                        // Handle is not string?
                        else
                        {
                            // Report warning.
                            trigger_error( "Invalid handle name for " .
                                           "dependency checking: $handle",
                                           E_USER_WARNING );
                        }
                    }

                    // Add to array.
                    $this->_depend[ $name ] = $list;

                    return( true );
                }

                // No class? XD
                else
                {
                    // Report warning.
                    trigger_error( "Dependency checking should only be used " .
                                   "for system plugins.",
                                   E_USER_WARNING );
                }
            }

            // List empty?
            else
            {
                // Report warning.
                trigger_error( "No dependency list provided.",
                               E_USER_WARNING );
            }

            return( false );
        }

        /**
        * Detach Event Listener
        *
        * This core method will "detach" (or remove) an event listener that
        * was attached by another core method called attach().  The arguments
        * provided to this method must be the same exact arguments as ones
        * provided to the attach() method.  A slight change in the arguments
        * will result in the wrong event listener being removed or no event
        * listener being removed at all.
        *
        * @access public
        * @uses   m_arg()
        * @uses   m_callback()
        * @uses   m_id()
        * @param  string  $event    Event name.
        * @param  mixed   $listener Event listener.
        * @return boolean
        */
        public function detach ( $event,
                                 $listener )
        {
            // Check arguments.
            m_arg( $event,           M_STRING   );
            m_arg( $listener, array( M_ARRAY,
                                     M_STRING ) );

            // Invalid callback?
            if ( !m_callback( $listener ) )
            {
                // Report warning.
                trigger_error( "Invalid event listener for event, $event, " .
                               "provided: $listener",
                               E_USER_WARNING );

                return( false );
            }

            // Generate ID.
            $id = m_id( $listener );

            // Remove.
            unset( $this->_event[ $event ][ $id ] );

            return( true );
        }

        /**
        * Load Library Plugin
        *
        * This core method will attempt to load the specified library plugin.
        * If the plugin has already been loaded, a warning will be triggered
        * and the boolean value of false will be returned.  If the plugin has
        * not been already loaded, it will check the plugin and attempt to
        * load it.  If the plugin does not exist or has permission errors, a
        * warning will be triggered and the boolean value of false will be
        * returned.  If the plugin is successfully loaded, the boolean value
        * of true will be returned.
        *
        * Note: The only way to keep track of loaded library plugins is to
        * use this method.  Please do not attempt to load library plugins
        * without using this core method.  Doing so may cause the system to
        * become unstable.
        *
        * @access public
        * @uses   m_arg()
        * @param  string  $plugin Library plugin name.
        * @return boolean
        */
        public function load ( $plugin )
        {
            // Check argument.
            m_arg( $plugin, M_STRING );

            // Plugin not loaded?
            if ( !in_array( $plugin, $this->_library ) )
            {
                // Create path.
                $path = M_LIBRARY_PATH . $plugin . M_EXT;

                // Library plugin exists?
                if ( m_path( $path, M_FILE, true ) )
                {
                    // Load plugin.
                    require_once( $path );

                    return( true );
                }

                // Plugin has errors?
                else
                {
                    // Report warning.
                    trigger_error( "Library plugin, $plugin, could not be " .
                                   "loaded.",
                                   E_USER_WARNING );
                }
            }

            // Plugin already loaded?
            else
            {
                // Report warning.
                trigger_error( "Library plugin, $plugin, has already been " .
                               "loaded by another plugin.",
                               E_USER_WARNING );
            }

            return( false );
        }

        /**
        * Register Event
        *
        * This core method registers an event with the system.  By registering
        * an event, you acknowledge the existance of the event so that other
        * plugins can determine whether or not to attach a listener.  You may
        * also "lock" an event to a specific function or method.  This will
        * restrict another core method called trigger() from being called by
        * any other function or method other than the one the event was
        * registered to.  The $reserved argument follows the same format as a
        * callback except it does not have to exist.  This will allow event
        * plugins to register events for a system plugin before the system
        * plugin is loaded.
        *
        * @access public
        * @uses   m_arg()
        * @uses   m_id()
        * @param  string  $event            Event name.
        * @param  mixed   $reserve optional Reserve for this function/method.
        * @return boolean
        */
        public function register ( $event,
                                   $reserve )
        {
            // Check arguments.
            m_arg( $event,          M_STRING          );
            m_arg( $reserve, array( M_ARRAY,
                                    M_STRING ), false );

            // System reserved event name?
            if ( $this->_reserved( $event ) )
            {
                // Report warning.
                trigger_error( "Event names prefiex with, m_, are "      .
                               "reserved for internal system processes " .
                               "only.",
                               E_USER_WARNING );

                return( false );
            }

            // Event not registered?
            if ( empty( $this->_registry[ $event ] ) )
            {
                // Have reserve?
                if ( !empty( $reserve ) )
                {
                    // Get caller ID.
                    if ( $id = m_id( $reserve ) )
                    {
                        // Add to registry.
                        $this->_registry[ $event ] = $id;

                        return( true );
                    }

                    // Invalid callback?
                    else
                    {
                        // Report warning.
                        trigger_error( "Unable to reserve event.  Invalid " .
                                       "function or method.",
                                       E_USER_WARNING );
                    }
                }

                // No reserve?
                else
                {
                    // Add to registry.
                    $this->_registry[ $event ] = true;

                    return( true );
                }
            }

            // Event registered?
            else
            {
                // Report warning.
                trigger_error( "Unable to reserve event.  Event already "     .
                               "registered to, " . $this->_registry[ $event ] .
                               ".",
                               E_USER_WARNING );
            }

            return( false );
        }

        /**
        * Event Registered?
        *
        * This core method simply checks to see if the specified event has
        * been registered with the system.  If the event has been registered,
        * the boolean value of true is returned.  If the event has not been
        * registered, the boolean value of false is returned.
        *
        * @access public
        * @uses   m_arg()
        * @param  string  $event Event name.
        * @return boolean
        */
        public function registered ( $event )
        {
            // Check argument.
            m_arg( $event, M_STRING );

            // Event registered?
            if ( !empty( $this->_registry[ $event ] ) )
            {
                // Yes.
                return( true );
            }

            return( false );
        }

        /**
        * Event Reserved?
        *
        * This core method simply checks to see if the specified event has
        * been reserved for another function or method.  If the event has been
        * reserved, the boolean value of true is returned.  If the event has
        * not been reserved, the boolean value of false is returned.
        *
        * @access public
        * @uses   m_arg()
        * @param  string  $event Event.
        * @return boolean
        */
        public function reserved ( $event )
        {
            // Check argument.
            m_arg( $event, M_STRING );

            // Event registered?
            if ( !empty( $this->_registry[ $event ] ) )
            {
                // Event has ID?
                if ( is_string( $this->_registry[ $event ] ) )
                {
                    // Yes.
                    return( true );
                }
            }

            return( false );
        }

        /**
        * Is System Plugin Loaded?
        *
        * This core method checks to see if the specified system plugin class
        * has been loaded on the specified handle.  I the handle is an object
        * and the class matches the class specified, the boolean value of true
        * will be returned.  If there are any discrepancies between the
        * arguments provided and the actual data, the boolean value of false
        * will be returned.
        *
        * @access public
        * @uses   m_arg()
        * @param  string  $handle Handle name.
        * @param  string  $class  System plugin class name.
        * @return boolean
        */
        public function system ( $handle,
                                 $class )
        {
            // Check arguments.
            m_arg( $handle, M_STRING );
            m_arg( $class,  M_STRING );

            // Handle set?
            if ( isset( $this->$handle ) &&
                 is_object( $this->$handle ) )
            {
                // Class match?
                if ( get_class( $this->$handle ) === $class )
                {
                    // Yes.
                    return( true );
                }
            }

            return( false );
        }

        /**
        * Trigger Event
        *
        * This core method executes all of the functions or methods listening
        * to the specified event.  If the event does not exist or there are no
        * listeners attached to the event, the boolean value of false will be
        * returned and no errors or warnings will be triggered.  If the event
        * has been registered to a specific function or method or is reserved
        * by the system, a warning will be triggered and the boolean value of
        * false will be returned.  If there are events and the event triggering
        * is allowed, all of the functions or methods will be executed with
        * the single argument provided (if any).  The argument passed to the
        * event listeners are passed by reference.
        *
        * @access public
        * @uses   m_arg()
        * @uses   Mukei::_reserved()
        * @param  string $event          Event name.
        * @param  mixed  $arg   optional Argument to pass to listeners.
        * @return boolean
        */
        public function trigger ( $event,
                                  &$arg = null )
        {
            // Check argument.
            m_arg( $event, M_STRING );

            // System reserved event name?
            if ( $this->_reserved( $event ) )
            {
                // Report warning.
                trigger_error( "Event names prefiex with, m_, are "      .
                               "reserved for internal system processes " .
                               "only.",
                               E_USER_WARNING );

                return( false );
            }

            // Reserved event name?
            if ( $this->reserved( $event ) )
            {
                // Invalid caller?
                if ( $this->_registry[ $event ] === m_cid( ) )
                {
                    // Report warning.
                    trigger_error( "Unable to trigger event.  Event, $event" .
                                   ", has been reserved for, "               .
                                   $this->_registry[ $event ] . ".",
                                   E_USER_WARNING );

                    return( false );
                }
            }

            // Event exists?
            if ( !empty( $this->_events[ $event ] ) )
            {
                // Walk through event listeners.
                foreach ( $this->_events[ $event ] as $listener )
                {
                    // Call event listener.
                    call_user_func_array( $listener,
                                          array( &$args ) );
                }

                return( true );
            }

            return( false );
        }

        /**
        * Unregister Event
        *
        * This core method "unregisters" an event previously registered by
        * another core method called register().  If the $clear argument is
        * set to true, it will remove all listeners attached to the specified
        * event.  If no checking is performed using the core methods
        * registered() or reserved(), a plugin may purposely or accidently
        * hijack an event that has been previously registered for another
        * function or method.
        *
        * @access public
        * @uses   m_arg()
        * @param  string  $event          Event name.
        * @param  boolean $clear optional Clear attached listeners?
        * @return boolean
        */
        public function unregister ( $event,
                                     $clear = false )
        {
            // Check arguments.
            m_arg( $event, M_STRING );
            m_arg( $clear, M_BOOL   );

            // Clear registry.
            unset( $this->_registry[ $event ] );

            // Clear listeners?
            if ( $clear === true )
            {
                // Clear listeners.
                unset( $this->_events[ $event ] );
            }

            return( true );
        }
    }

    /**
    * Argument Validator
    *
    * This core function will perform a series of checks on the argument
    * provided to make sure the caller receives what was expected.  If the
    * argument is empty and the caller requires the variable's contents ($req
    * equals true), a fatal error will be triggered.  If the variable's type
    * is does not match the type(s) allowed, a fatal error will be triggered.
    * This function is used to prevent unexpected results from variables that
    * contain invalid data.  The variables types supported may be expanded by
    * event plugins in the "m_define_pre" or "m_define_post" events.  However,
    * modification of the original data types is not allowed.
    *
    * @uses   m_cid()
    * @uses   m_type()
    * @param  mixed   $var            Variable to validate.
    * @param  string  $types          Argument type(s) allowed.
    * @param  boolean $req   optional Argument required?
    * @return boolean
    */
    function m_arg ( $var,
                     $types,
                     $req = true )
    {
        // Single type?
        if ( !is_array( $types ) )
        {
            // Make into array.
            $types = array( $types );
        }

        // Get variable type.
        $type = m_type( $var );

        // Accepted?
        $accept = in_array( $type, $types );

        // Acquire caller ID.
        $id = m_cid( );

        // Missing variable?
        if ( empty      ( $var ) &&
             !is_numeric( $var ) &&
             !is_bool   ( $var ) &&
             ( $req === true  ) )
        {
            // Report fatal error.
            trigger_error( "$id: Argument required.",
                           E_USER_ERROR );
        }

        // Invalid argument type?
        if ( $accept === false )
        {
            // Get type.
            $temp = array_pop( $types );

            // Have more?
            if ( !empty( $types ) )
            {
                // Update $temp.
                $temp = join( ", ", $types ) . " or $temp";
            }

            // Report fatal error.
            trigger_error( "$id: Expecting $temp, received $type.",
                           E_USER_ERROR );
        }

        return( true );
    }

    /**
    * Validate Callback
    *
    * This core function will check the provided $callback argument to see if
    * it is indeed a valid callback.  According to the PHP documentation, a
    * valid callback is a function's string name, an array with the string
    * name of the class and the string name of a method, or an array with the
    * class object and the string name of the method.  If provided $callback
    * argument does not match any of those conditions, a warning will be
    * triggered and the boolean value of false will be returned.  If $exist is
    * set to true and the the callback function or method does not exist, an
    * error will be triggered and the boolean value of false will be returned.
    *
    * @link   http://us3.php.net/callback#language.types.callback
    * @param  mixed   $callback          Callback to validate.
    * @param  boolean $exist    optional Callback must exist?
    * @return boolean
    */
    function m_callback ( $callback,
                          $exist = true )
    {
        // Not a string or array?
        if ( !is_string( $callback ) &&
             !is_array ( $callback ) )
        {
            // Report warning.
            trigger_error( "Invalid callback: $callback",
                           E_USER_WARNING );

            return( false );
        }

        // Is a string?
        if ( is_string( $callback ) )
        {
            // Function does not exist?
            if ( !function_exists( $callback ) )
            {
                // Report warning.
                trigger_error( "Callback function, $callback, does not " .
                               "exist.",
                               E_USER_WARNING );
            }

            // Function exists?
            else
            {
                // Success.
                return( true );
            }
        }

        // Is an array?
        else
        {
            // Get class.
            $class = is_object( $callback[0] ) ? get_class( $callback[0] )
                                               : "";

            // Invalid callback count?
            if ( ( $count = count( $callback ) ) !== 2 )
            {
                // Report warning.
                trigger_error( "Invalid callback array count: $count",
                               E_USER_WARNING );
            }

            // Invalid class?
            elseif ( ( $exist === true ) &&
                     !is_string( $callback[0] ) &&
                     !is_object( $callback[0] ) )
            {
                // Report warning.
                trigger_error( "Invalid callback class: " . $callback[0],
                               E_USER_WARNING );
            }

            // Invalid method?
            elseif ( ( $exist === true ) &&
                     !is_string( $callback[1] ) )
            {
                // Report warning.
                trigger_error( "Invalid callback method: " . $callback[1],
                               E_USER_WARNING );
            }

            // Class does not exist?
            elseif ( ( $exist === true ) &&
                     is_string( $callback[0] ) &&
                     !class_exists( $callback[0] ) )
            {
                // Report warning.
                trigger_error( "Callback class, " . $callback[0] . ", " .
                               "does not exist.",
                               E_USER_WARNING );
            }

            // Invalid object?
            elseif ( is_object( $callback[0] ) &&
                     ( empty( $class ) ||
                       ( $class === "stdClass" ) ) )
            {
                // Report warning.
                trigger_error( "Invalid callback object: " . $callback[0],
                               E_USER_WARNING );
            }

            // Method does not exist?
            elseif ( ( $exist === true ) &&
                     !method_exists( $callback[0],
                                     $callback[1] ) )
            {
                // Get class.
                $class = !empty( $class ) ? $class
                                          : $callback[0];

                // Report warning.
                trigger_error( "Callback method, " . $callback[1] . ", " .
                               "in class, $class, does not exist.",
                               E_USER_WARNING );
            }

            // No errors?
            else
            {
                // Success.
                return( true );
            }
        }

        return( false );
    }

    /**
    * Caller ID
    *
    * This core function generates a unique identifier for the caller of a
    * function.  Which caller the identifier is generated for depends on what
    * the offset is set to.  By default, this function will generate the
    * identifier of the caller of the function or method that called this
    * function.  The offset is used in the array that is returned by the PHP
    * debug_backtrace() function.  The number 2 will always be added to the
    * function.  This makes the offset argument more relative than an
    * absolute.  If the offset is not an integer or does not exist as an index
    * in the array returned by debug_backtrace(), a warning will be triggered
    * and the boolean value of false will be returned.
    *
    * @access public
    * @param  integer $offset Caller offset.
    * @return string
    */
    function m_cid ( $offset = 0 )
    {
        // Invalid offset type?
        if ( !is_integer( $offset ) )
        {
            // Report warning.
            trigger_error( "m_cid(): Invalid offset, $offset.",
                           E_USER_WARNING );

            return( false );
        }

        // Increment offset.
        $offset += 2;

        // Get history.
        $history = debug_backtrace( );

        // Offset out of bounds?
        if ( empty( $history[ $offset ] ) )
        {
            // Report warning.
            trigger_error( "m_cid(): Offset, $offset, out of bounds.",
                           E_USER_WARNING );

            return( false );
        }

        // Get caller.
        $history = $history[ $offset ];

        // Begin caller ID.
        $caller = $history['function'];

        // Have class?
        if ( !empty( $history['class'] ) )
        {
            // Update caller ID.
            $caller = $history['class'] .
                      $history['type']  .
                      $caller;
        }

        // Finish caller ID.
        $caller .= "()";

        return( $caller );
    }

    /**
    * Local Data Storage
    *
    * This core function provides a way to store and retrieve data without the
    * use of a database.  However, it is only suggested for use with saving
    * configuration settings and similar data that is crucial for the operation
    * of the system or plugin.  Because of the format of the file, it is not
    * suggested that large quantities of data be stored.  Since this function
    * uses the PHP serialize() and unserialize() functions, certain types of
    * variables cannot be stored.
    *
    * If only the $name argument is provided, an attempt will be made to
    * retrieve the settings from the specified file.  If the file does not
    * exist or is invalid, a warning will be triggered and the boolean value
    * of false will be returned.  Otherwise the retrieved data will be
    * returned.  If the $value argument is also provided, an attempt will be
    * made to serialize and store the data in the specified file.  If the
    * data could not be serialized or saved to the specified file, a warning
    * will be triggered and the boolean value of false will be returned.
    * Otherwise if it is successful, the boolean value of true will be
    * returned.
    *
    * Warning: This is not a secure method of storing sensitive information
    * such as passwords and other forms of private data.  It is suggested that
    * the data be encrypted before passing the value to this function or find
    * another method of storing the data.
    *
    * @uses   m_arg()
    * @uses   m_data_create()
    * @uses   m_data_parse()
    * @uses   m_path()
    * @param  string $name           Local data file namespace.
    * @param  mixed  $value optional Local data file value.
    * @return mixed
    */
    function m_data ( $name,
                      $value = null )
    {
        // Check argument.
        m_arg( $name, M_STRING );

        // Create path.
        $path = M_DATA_DIR . $name . M_EXT;

        // Have value?
        if ( !is_null( $value ) )
        {
            // Data file exist?
            if ( @m_path( $path, M_FILE ) )
            {
                // Is not writable?
                if ( !m_path( $path, M_FILE, true, true ) )
                {
                    // Report warning.
                    trigger_error( "Existing data file, $name, cannot be " .
                                   "overriden.",
                                   E_USER_WARNING );

                    return( null );
                }
            }

            // Attempt to create data.
            if ( $value = m_data_create( $value ) )
            {
                // Attempt to save.
                if ( file_put_contents( $path, $value ) )
                {
                    // Success.
                    return( true );
                }

                // Unable to save?
                else
                {
                    // Report warning.
                    trigger_error( "Unable to save data file, $name.",
                                   E_USER_WARNING );
                }
            }

            // Cannot create data?
            else
            {
                // Report warning.
                trigger_error( "Unable to create data file, $name.",
                               E_USER_WARNING );
            }
        }

        // No value?
        else
        {
            // Check path.
            if ( m_path( $path, M_FILE, true ) )
            {
                // Attempt to read contents.
                if ( $value = file_get_contents( $path ) )
                {
                    // Attempt to parse.
                    if ( ( $value = m_data_parse( $value ) ) !== false )
                    {
                        // Success.
                        return( $value );
                    }

                    // Unable to parse?
                    else
                    {
                        // Report warning.
                        trigger_error( "Unable to parse data file, $name.",
                                       E_USER_WARNING );
                    }
                }

                // Unable to read?
                else
                {
                    // Report warning.
                    trigger_error( "Unable to read data file, $name.",
                                   E_USER_WARNING );
                }
            }

            // Invalid path?
            else
            {
                // Report warning.
                trigger_error( "Data file, $name, has errors.",
                               E_USER_WARNING );
            }
        }

        return( null );
    }

    /**
    * Create Data File Contents
    *
    * This core function simply creates the string data that would be stored
    * in a data file by another core function called, m_data().  However this
    * process has been seperated from the actual storing procedure so that the
    * database can be stored in other locations such as databases.  The $value
    * argument provided is serialized and stored as a comment enclosed in the
    * <?php ?> tags, each on its own line.  This prevent people from viewing
    * the contents of the data file from a browser or other method.
    *
    * @see    m_data_parse()
    * @param  mixed $value Contents to convert.
    * @return string
    */
    function m_data_create ( $value )
    {
        // Serialized data?
        if ( $data = serialize( $value ) )
        {
            // Create data file contents.
            $file  = "<?php\n";
            $file .= "#$data\n";
            $file .= "?>";

            return( $file );
        }

        // Unable to serialize?
        else
        {
            // Report warning.
            trigger_error( "Unable to serialize data.",
                           E_USER_WARNING );
        }

        return( false );
    }

    /**
    * Parse Data File Contents
    *
    * This core function parses the data generated by another core function
    * called, m_data_create().  If the system has been relocated to another
    * operating system where newline character is translated differently, PHP's
    * unserialize() function may not be able to reverse the changes made to
    * the data.  If the $data argument does not contain the same formatted data
    * that the core function m_data_create() would return, a warning will be
    * triggered and the value of null will be returned.  If the data is
    * successfully parsed and unserialized, the resulting data will be
    * returned.
    *
    * @uses   m_arg()
    * @param  string $data Data to parse.
    * @return mixed
    */
    function m_data_parse ( $data )
    {
        // Check argument.
        m_arg( $data, M_STRING );

        // First parse.
        $data = explode( "\n", $data );

        // Valid line count?
        if ( count( $data ) === 3 )
        {
            // Valid data line?
            if ( substr( $data[1], 0, 1 ) === "#" )
            {
                // Extract data.
                $data = substr( $data[1], 1 );
                $data = trim( $data );

                // Not empty?
                if ( !empty( $data ) )
                {
                    // Unserialize.
                    $original = unserialize( $data );

                    // Invalid return?
                    if ( ( $original === false ) &&
                         ( $data     !== serialize( false ) ) )
                    {
                        // Report warning.
                        trigger_error( "Unable to unserialize data.",
                                       E_USER_WARNING );
                    }

                    // Valid return?
                    else
                    {
                        // Success.
                        return( $original );
                    }
                }

                // Empty?
                else
                {
                    // Report warning.
                    trigger_error( "Empty data line in data file.",
                                   E_USER_WARNING );
                }
            }

            // Invalid data line?
            else
            {
                // Report warning.
                trigger_error( "Invalid data line in data file.",
                               E_USER_WARNING );
            }
        }

        // Invalid line count?
        else
        {
            // Report warning.
            trigger_error( "Invalid line count in data file.",
                           E_USER_WARNING );
        }

        return( null );
    }

    /**
    * Declare If Not Exists
    *
    * This core function will define the specified constant with the specified
    * value only if it does not exist.  The parameters are the same as PHP's
    * define() function.  This function is useful for cases where constants
    * are expected to be already defined but is used as a backup in case the
    * constant has not been defined.  This function also performs checks on the
    * $value argument since constants cannot hold variables of all data types.
    * If the constant was defined, the boolean value of true will be returned.
    * If the constant was already defined or could not be defined, the boolean
    * value of false will be returned.
    *
    * @uses   m_arg()
    * @param  string  $name           Name of the constant.
    * @param  mixed   $value          Value of the constant.
    * @param  boolean $case  optional Is case sensitive?
    * @return boolean
    */
    function m_define ( $name,
                        $value,
                        $case = true )
    {
        // Check arguments.
        m_arg( $name,         M_STRING );
        m_arg( $value, array( M_BOOL,
                              M_DOUBLE,
                              M_INTEGER,
                              M_NULL,
                              M_STRING ) );

        // Constant not declared?
        if ( !defined( $name ) )
        {
            // Declare the constant.
            if ( define( $name,
                         $value,
                         $case ) )
            {
                // Success.
                return( true );
            }
        }

        return( false );
    }

    /**
    * Retrieve Global
    *
    * This core function attempts to retrieve the globals specified in the
    * order specified.  If the first specified global does not exist, it will
    * check to see if the next in the list exists.  This process will continue
    * until the list is exhausted or when a global is found.  If a global is
    * found, it will be returned by reference.  If no global is found, the
    * boolean value of false will be returned.
    *
    * @uses   m_arg()
    * @param  string $global,... Global name(s).
    * @return mixed
    */
    function &m_global ( )
    {
        // Get list of globals.
        $globals = func_get_args( );

        // Walk through array.
        foreach ( $globals as $global )
        {
            // Check argument.
            m_arg( $global, M_STRING );

            // Fetch global.
            global $$global;

            // Global exists?
            if ( isset( $$global ) )
            {
                // Return by reference.
                return( $$global );
            }
        }

        return( false );
    }

    /**
    * Callback Identifer
    *
    * This core function will generate a unique identifier for the $callback
    * argument provided.  If the callback is a function name, the identifier
    * returned will look similar to this: function_name().  If the callback
    * is an array with the string class name and the string method name, the
    * identifier returned will look similar to this: Class_Name::method_name().
    * If the callback is an array with a class object and a string method name,
    * the identifier returned will look similar to this:
    * Class_Name->method_name().  This open and close parentheses at the end of
    * the identifier will never change and will never contain any arguments
    * passed to the function or method.
    *
    * @uses   m_arg()
    * @uses   m_callback()
    * @param  mixed  $callback Callback to ID.
    * @return string
    */
    function m_id ( $callback )
    {
        // Check argument.
        m_arg( $callback, array( M_ARRAY,
                                 M_STRING ) );

        // Invalid callback?
        if ( !m_callback( $callback, false ) )
        {
            // Report warning.
            trigger_error( "Cannot generate callback ID.",
                           E_USER_WARNING );

            return( false );
        }

        // Is string?
        if ( is_string( $callback ) )
        {
            // Create ID.
            $callback .= "()";
        }

        // Is array?
        else
        {
            // Is object?
            if ( is_object( $callback[0] ) )
            {
                // Create ID.
                $callback = get_class( $callback[0] ) .
                            "->" . $callback[1] . "()";
            }

            // Is static?
            else
            {
                // Create ID.
                $callback = $callback[0] . "::" .
                            $callback[1] . "()";
            }
        }

        return( $callback );
    }

    /**
    * Validate Path
    *
    * This core function will perform a series of checks on the path provided.
    * If the path provided does not exist, or match the type specified by the
    * $type argument, a warning will be triggered and the boolean value of
    * false will be returned.  If $read or $write is set to true, this function
    * will check for read and/or write permissions.  If the user and group used
    * to execute Mukei does not have permission to read or write to the
    * specified path, a warning will be triggered and the boolean value of
    * false will be returned.
    *
    * @uses   m_arg()
    * @uses   m_cid()
    * @param  string  $path           Path to validate.
    * @param  string  $type           Path must be this type.
    * @param  boolean $read  optional Check for read permission?
    * @param  boolean $write optional Check for write permission?
    * @return boolean
    */
    function m_path ( $path,
                      $type,
                      $read  = false,
                      $write = false )
    {
        // Check arguments.
        m_arg( $path,  M_STRING );
        m_arg( $type,  M_STRING );
        m_arg( $read,  M_BOOL   );
        m_arg( $write, M_BOOL   );

        // Path exists?
        if ( file_exists( $path ) )
        {
            // Path type valid?
            if ( ( is_dir( $path ) &&
                   ( $type === M_DIRECTORY ) ) ||
                 ( is_file( $path ) &&
                   ( $type === M_FILE ) ) )
            {
                // Check for read permission?
                if ( ( $read === true ) &&
                     !is_readable( $path ) )
                {
                    // Report warning.
                    trigger_error( m_cid( ) . ": Path, $path, is not " .
                                   "readable by the system.",
                                   E_USER_WARNING );
                }

                // Check for write permission?
                elseif ( ( $write === true ) &&
                         !is_writable( $path ) )
                {
                    // Report warning.
                    trigger_error( m_cid( ) . ": Path, $path, is not " .
                                   "writable by the system.",
                                   E_USER_WARNING );
                }

                // All checks passed?
                else
                {
                    // Success.
                    return( true );
                }
            }

            // Invalid path type?
            else
            {
                // Initialize $recvd.
                $recvd = is_dir( $path ) ? M_DIRECTORY
                                         : M_FILE;

                // Report warning.
                trigger_error( m_cid( ) . ": Expecting $type path, received " .
                               "$recvd path.",
                               E_USER_WARNING );
            }
        }

        // Path does not exist?
        else
        {
            // Report warning.
            trigger_error( m_cid( ) . ": Path, $path, does not exist.",
                           E_USER_WARNING );
        }

        return( false );
    }

    /**
    * Scan Directory w/ Filtering
    *
    * This core function will perform the same function as PHP's scandir() but
    * introduces two new features: a scanning mode and a Perl regular
    * expression filter.  There are two possible scanning modes: M_FILE will
    * make this function only scan for files (per is_file()), and M_DIRECTORY
    * will only scan for directories (per is_dir()).  These two modes can be
    * used in conjunction with the regular expression filter to narrow the
    * search for files that will be returned.  For the regular expression
    * filter, the PHP function preg_match() is used.  If the preg_match()
    * returns false, the item will be removed from the results returned.
    *
    * @uses   m_arg()
    * @uses   m_path()
    * @link   http://us.php.net/manual/en/ref.stream.php#stream.contexts
    * @param  string   $path           Directory path to scan.
    * @param  string   $mode  optional Scanning mode.
    * @param  string   $regex optional Regular expression filter.
    * @param  integer  $sort  optional Sorting order.
    * @param  resource $io    optional Any valid stream context.
    * @return array
    */
    function m_scan ( $path,
                      $mode  = "",
                      $regex = "",
                      $sort  = 0,
                      $io    = null )
    {
        // Check arguments.
        m_arg( $path,         M_STRING          );
        m_arg( $mode,         M_STRING,   false );
        m_arg( $regex,        M_STRING,   false );
        m_arg( $sort,         M_INTEGER,  false );
        m_arg( $io,    array( M_RESOURCE,
                              M_NULL   ), false );

        // Directory exists?
        if ( m_path( $path, M_DIRECTORY, true ) )
        {
            // Initialize $contents.
            $contents = array( );

            // Resource scan?
            if ( !is_null( $io ) )
            {
                // Scan.
                $contents = scandir( $path, $sort, $io );
            }

            // Regular scan?
            else
            {
                // Scan.
                $contents = scandir( $path, $sort );
            }

            // Attempt scan.
            if ( $contents !== false )
            {
                // Walk through contents.
                foreach ( $contents as $index => $content )
                {
                    // Create path.
                    $c_path = $path . M_SEP . $content;

                    // Is current or parent?
                    if ( ( $content === "."  ) ||
                         ( $content === ".." ) )
                    {
                        // Remove.
                        unset( $contents[ $index ] );
                    }

                    // Mode filtered?
                    elseif ( ( !is_dir( $c_path ) &&
                               ( $mode === M_DIRECTORY ) ) ||
                             ( !is_file( $c_path ) &&
                               ( $mode === M_FILE ) ) )
                    {
                        // Remove.
                        unset( $contents[ $index ] );
                    }

                    // Regex filtered?
                    elseif ( !empty( $regex ) &&
                             !preg_match( $regex, $content ) )
                    {
                        // Remove.
                        unset( $contents[ $index ] );
                    }
                }

                // Reset indexes.
                $contents = array_values( $contents );

                return( $contents );
            }
        }

        return( false );
    }

    /**
    * Get Variable Type
    *
    * This core function simply returns the variable type of the $var argument
    * provided.  The variable types discovered are limited to the PHP is_*
    * functions.  The value returned is from the M_* type constants declared by
    * the core class (Mukei).  If the type of the argument is not recognized
    * by this function, the value of M_UNKNOWN will be returned.  It is
    * recommended that the M_* type constants be used instead of their actual
    * values.  Using the M_* type constants will allow for compatibilty with
    * future version of the system.
    *
    * @see    Mukei::_define()
    * @param  mixed  $var Variable to get type of.
    * @return string
    */
    function m_type ( $var )
    {
        // Initialize $type.
        $type = "";

        // Get type.
        if     ( is_array   ( $var ) ) $type = M_ARRAY;
        elseif ( is_bool    ( $var ) ) $type = M_BOOL;
        elseif ( is_double  ( $var ) ) $type = M_DOUBLE;
        elseif ( is_integer ( $var ) ) $type = M_INTEGER;
        elseif ( is_null    ( $var ) ) $type = M_NULL;
        elseif ( is_object  ( $var ) ) $type = M_OBJECT;
        elseif ( is_resource( $var ) ) $type = M_RESOURCE;
        elseif ( is_string  ( $var ) ) $type = M_STRING;
        else                           $type = M_UNKNOWN;

        return( $type );
    }

?>